<!-- 左右/上下 可改变大小区域 -->
<template>
  <div class="areaMoveX">

    <!-- region 左右 -->
    <div class="leftRightBox" v-if="props.leftRight" ref="leftRightDom">

      <div class="leftBox" ref="leftDom" :style="leftStyle">
        <!-- 左边/上边 -->
        <slot name="lt"/>
      </div>

      <div class="lfLineBox" ref="lrLineDom" v-if="!noLine"
           @mousedown="clickLineFn">
        <!-- region 中间线 -->
        <slot name="line">
          <div class="lineBox" :class="props.lineClass">
            <div class="line"></div>
            <div class="iconBox" v-if="props.showIcon" @click="clickLRIconFn">
              <icon-x class="iconItem lrIcon"
                      size="20" :type="lrIcon"/>
            </div>
          </div>
        </slot>
        <!-- endregion -->
      </div>

      <div class="rightBox" ref="rightDom" :style="rightStyle">
        <!-- 右边/下边 -->
        <slot name="rb"/>
      </div>

    </div>
    <!-- endregion -->

    <!-- region 上下 -->
    <div class="topBottomBox" v-else ref="topBottomDom">

      <div class="topBox" ref="topDom" :style="topStyle">
        <!-- 左边/上边 -->
        <slot name="lt"/>
      </div>

      <div class="tbLineBox" ref="tbLineDom" v-if="!noLine" @mousedown="clickLineFn">
        <!-- region 中间线 -->
        <slot name="line">
          <div class="lineBox" :class="props.lineClass">
            <div class="line"></div>
            <div class="iconBox" v-if="props.showIcon" @click="clickTBIconFn">
              <icon-x class="iconItem tnIcon"
                      size="20" :type="tbIcon"/>
            </div>
          </div>
        </slot>
        <!-- endregion -->
      </div>

      <div class="bottomBox" ref="bottomDom" :style="bottomStyle">
        <!-- 右边/下边 -->
        <slot name="rb"/>
      </div>

    </div>
    <!-- endregion -->

  </div>
</template>

<script setup>
import {ref, computed,watch,onMounted} from 'vue'
import IconX from '../element/xhykIcon.vue'
defineOptions({name: "areaMoveX"})
const props = defineProps({
  // 上下还是左右(默认左右)
  leftRight: {
    type: Boolean,
    default: true
  },

  // 初始化左边/上边的宽度
  ltWidth: {
    type: [String, Number],
    default: 'auto'
  },

  // 左边/上边最小宽度
  minWidth: {
    type: [Number, String],
    default: 'auto'
  },

  // 右/下最小宽度
  lbMinWidth: {
    type: [Number, String],
    default: 'auto'
  },


  // region 中间线配置

  // 中间线宽度
  lineWidth: {
    type: [String, Number],
    default: '4px'
  },

  // 中间线活跃时的颜色，为了设置系统配色
  lineColorFn: {
    type: Function,
    default: undefined
  },

  // 中间线样式
  lineClass: {
    type: [Object,String],
    default: 'moveLine'
  },

  // 是否不显示中间线
  noLine: {
    type: Boolean,
    default: false
  },

  // 中间线是否可用
  disabled: {
    type: Boolean,
    default: false
  },

  // 是否显示中间线控件
  showIcon: {
    type: Boolean,
    default: false
  },

  // 左右进行反向收缩
  direction: {
    type: Boolean,
    default: false
  },

  // endregion

  // 加载完成后调用，用来修改样式
  afterLoad: {
    type: Function,
    default: undefined
  },
})

const emit = defineEmits(['move', 'down'])

// region 工具类
// 判断prop传参的值。接受[String,Number]的style样式尺寸
function getPx(text, defaultPx = 'px') {
  let tempList = ['px', 'rpx', 'vw', 'vh', '%', 'em', 'auto']
  if (typeof text == 'string') {
    const havePx = tempList.find(row => text.includes(row))
    if (havePx) {
      return text
    } else {
      return `${parseFloat(text)}${defaultPx}`
    }
  } else if (typeof text == 'number') {
    let temp = parseFloat(text)
    return `${temp}${defaultPx}`
  }
  return text
}

// 触发窗口变化
function resizeFn() {
  // 创建一个 Event 对象，指定事件类型为 'resize'
  let resizeEvent = new Event('resize');

  // 分发 resize 事件到 window 对象
  window.dispatchEvent(resizeEvent);
}
// endregion


// region 元素对象

// 左右父级对象
const leftRightDom = ref({})

// 左边对象
const leftDom = ref({})

// 左右布局中间线对象
const lrLineDom = ref({})

// 右边对象
const rightDom = ref({})


// 上下父级对象
const topBottomDom = ref({})

// 上边对象
const topDom = ref({})

// 上下布局中间线对象
const tbLineDom = ref({})

// 下边对象
const bottomDom = ref({})

// endregion


// region 元素样式

// 左边样式
const leftStyle = ref({})
// 当宽度为零时，display为none
watch(() => leftStyle.value, (newV, oldV) => {
  leftStyle.value.display = parseFloat(leftStyle.value.width) == 0 && !props.direction ? 'none' : 'block'
}, {immediate: true, deep: true})

// 右边样式。这个width属性是无效的，因为是flex: 1 1 auto;只能通过修改leftStyle来修改这个width
const rightStyle = ref({})
// 恢复右边宽度：左边flex宽度 = 父级 - 右/下边最小宽度 - 中间线
const computedRightWidthFn = () => {
  const fatherWidth = parseFloat(window.getComputedStyle(leftRightDom.value).width)
  const lineWidth = parseFloat(window.getComputedStyle(lrLineDom.value).width)
  const minRightWidth = parseFloat(props.lbMinWidth)
  if (!isNaN(minRightWidth)) {
    leftStyle.value.width = `${fatherWidth - lineWidth - minRightWidth}px`
  }
}

// 上边样式
const topStyle = ref({})

// 下边样式
const bottomStyle = ref({})
// 恢复下边高度：上边flex高度 = 父级 - 右/下边最小宽度 - 中间线
const computedBottomHeightFn = () => {
  const fatherWidth = parseFloat(window.getComputedStyle(topBottomDom.value).height)
  const lineWidth = parseFloat(window.getComputedStyle(tbLineDom.value).height)
  const minRightWidth = parseFloat(props.lbMinWidth)
  if (!isNaN(minRightWidth)) {
    bottomStyle.value.height = `${fatherWidth - lineWidth - minRightWidth}px`
  }
}

// endregion


// region 监听事件

// 上一次移动宽度
const lastNowWidth = ref(0)
// 上一次移动高度
const lastNowHeight = ref(0)

// 移动事件，处理宽高
function moveFn(eventMove) {
  // 左右排版
  if (props.leftRight == true) {

    // region 如果是点击收缩的，此时停止拖到行为
    if (clickWidthLog.value) {
      return;
    }
    // endregion

    // 获取元素左边的X轴位置
    const elmentLeftX = leftDom.value.getBoundingClientRect().left
    // 中间控制器宽度
    const tempWidth = parseFloat(window.getComputedStyle(lrLineDom.value).width)
    let nowWidth = eventMove.x - tempWidth / 2 - elmentLeftX
    emit('move', {
      eventMove,
      width: nowWidth
    })
    resizeFn()

    // 判断左边是否到达最小宽度
    const tempW = parseFloat(props.minWidth)
    if (nowWidth <= tempW) {
      return;
    }

    // 取右边宽度，判断右边是否到达最小宽度
    if (!isNaN(parseFloat(props.lbMinWidth))) {
      const rightWidth = parseFloat(window.getComputedStyle(rightDom.value).width)
      if (rightWidth <= parseFloat(props.lbMinWidth) && lastNowWidth.value < nowWidth) {
        computedRightWidthFn()
        return;
      }
    }


    // 修改左边宽度
    if (props.disabled != true) {
      leftStyle.value.width = `${nowWidth}px`
      lastNowWidth.value = nowWidth
    }
  } else {

    // 获取元素左边的X轴位置
    const elmentTopX = topDom.value.getBoundingClientRect().top
    // 中间控制器宽度
    const tempWidth = parseFloat(window.getComputedStyle(tbLineDom.value).height)
    let nowHeight = eventMove.y - tempWidth / 2 - elmentTopX
    emit('move', {
      eventMove,
      width: nowHeight
    })
    resizeFn()

    const tempH = parseFloat(props.minWidth)
    if (nowHeight <= tempH) {
      return;
    }

    // 取右边宽度
    if (!isNaN(parseFloat(props.lbMinWidth))) {
      const bottomHeight = parseFloat(window.getComputedStyle(bottomDom.value).height)
      if (bottomHeight <= parseFloat(props.lbMinWidth) && lastNowHeight.value < nowHeight) {
        computedBottomHeightFn()
        return;
      }
    }


    // 修改左边宽度
    if (props.disabled != true) {
      topStyle.value.height = `${nowHeight}px`
      lastNowHeight.value = nowHeight
    }

  }
}

// 鼠标移出dom时
const mouseOutFn = (e) => {
  // 判断是否为顶层
  if (e.toElement) {
    let thisDomName = e.toElement.nodeName
    if (thisDomName == 'HTML') {
      clearFn()
    }
  }
}

// 清空监听
const clearFn = () => {
  document.removeEventListener('mousemove', moveFn)
  document.removeEventListener('mouseout', mouseOutFn)
}


// 鼠标放开事件
document.addEventListener('mouseup', () => {
  clearFn()
})
// endregion


// region 中间线的样式/事件

// 中间线颜色
const lineColorValue = computed(() => {
  if (typeof props.lineColorFn == 'function') {
    return props.lineColorFn(props.disabled, 'line')
  }
  if (props.disabled || clickWidthLog.value) {
    return '#dcdfe6'
  } else {
    return '#409EFF'
  }
})

// 点击了中间线
const clickLineFn = (e) => {
  emit("down", e)
  document.addEventListener('mousemove', moveFn)
  document.addEventListener('mouseout', mouseOutFn)
}

// 中间线的宽度
const lineActiveWidth = computed(() => {
  return getPx(props.lineWidth)
})

// 中间线手指类型
const lineIcon = computed(() => {
  if (props.disabled || clickWidthLog.value) {
    return 'default'
  } else if (props.leftRight) {
    return 'col-resize'
  } else {
    return 'row-resize'
  }
})


// endregion


// region 中间线的收缩图标。初始化宽高

// 收缩图标的颜色
const lineIconControllColor = computed(() => {
  if (typeof props.lineColorFn == 'function') {
    return props.lineColorFn(props.disabled, 'lineIcon')
  }
  return '#409EFF'
})

// 左右区域的中间收缩图标
const lrIcon = computed(() => {
  if (!props.direction) {
    // 如果左边宽度为0，此时图标为向右
    const leftWidth = parseFloat(leftStyle.value.width)
    if (isNaN(leftWidth) || leftWidth == 0) {
      return 'Expand'
    }
    return 'Fold'
  } else {
    // 如果左边宽度为：父组件宽度 - 中间线宽度，此时图标为向左（已经处于收缩状态）
    try {
      const fatherWidth = parseFloat(window.getComputedStyle(leftRightDom.value).width)
      const lineWidth = parseFloat(window.getComputedStyle(lrLineDom.value).width)
      const leftWidth = `${fatherWidth - lineWidth}px`
      if (leftStyle.value.width != leftWidth) {
        return 'Expand'
      }
    } catch (err) {

    }
    return 'Fold'
  }
})

// 上下区域的中间收缩图标
const tbIcon = computed(() => {
  // 如果左边宽度为0，此时图标为向右
  const topHeight = parseFloat(topStyle.value.height)
  if (isNaN(topHeight) || topHeight == 0) {
    return 'Expand'
  }
  return 'Fold'
})


// 记录点击时宽度。不为空时说明是收缩
const clickWidthLog = ref('')

// 点击了左右的隐藏图标
const clickLRIconFn = () => {
  if (!props.direction) {
    // 正向收缩
    if (lrIcon.value == 'Fold') {
      clickWidthLog.value = leftStyle.value.width
      leftStyle.value.width = `0px`
      return
    }
  } else {
    // 方向收缩
    if (lrIcon.value == 'Expand') {
      clickWidthLog.value = leftStyle.value.width
      const fatherWidth = parseFloat(window.getComputedStyle(leftRightDom.value).width)
      const lineWidth = parseFloat(window.getComputedStyle(lrLineDom.value).width)
      leftStyle.value.width = `${fatherWidth - lineWidth}px`
      return
    }
  }
  leftStyle.value.width = clickWidthLog.value ? clickWidthLog.value : initFn()
  clickWidthLog.value = ''
}

// 点击了上下的隐藏图标
const clickTBIconFn = () => {
  if (tbIcon.value == 'Fold') {
    clickWidthLog.value = topStyle.value.height
    topStyle.value.height = `0px`
  } else {
    topStyle.value.height = clickWidthLog.value ? clickWidthLog.value : initFn()
    clickWidthLog.value = ''
  }
}

// endregion


// region 初始化宽度
// 初始化宽度
const initFn = () => {
  const firstWidth = isNaN(parseFloat(props.ltWidth)) ? 0 : parseFloat(props.ltWidth)
  const minWidth = isNaN(parseFloat(props.minWidth)) ? 0 : parseFloat(props.minWidth)
  const newWidth = minWidth > firstWidth ? getPx(props.minWidth) : getPx(props.ltWidth)
  leftStyle.value.width = `${newWidth}`
  topStyle.value.height = `${newWidth}`
  if (typeof props.afterLoad == 'function') {
    props.afterLoad(leftStyle.value, topStyle.value)
  }
}

watch(() => props.minWidth, (newV, oldV) => {
  initFn()
}, {immediate: true, deep: true})

// endregion


// region 暴露给父级。修改样式
defineExpose({
  initFn,
  leftStyle,
  rightStyle,
  topStyle,
  bottomStyle,
  leftRightDom,
  leftDom,
  lrLineDom,
  rightDom,
  topBottomDom,
  topDom,
  tbLineDom,
  bottomDom,

  // region 处理中间线插槽时的点击收缩事件
  lrIcon,
  hiddenLR: clickLRIconFn,
  tbIcon,
  hiddrenTB: clickTBIconFn,
  // endregion
})
// endregion

onMounted(() => {
  initFn()
})
</script>

<style scoped lang='scss'>
.areaMoveX {
  width: 100%;
  height: 100%;
}

.publicLine {
  flex: 0 0 auto;
  user-select: none;
  .lineBox {
    height: 100%;
    position: relative;
  }

  .line {
    background-color: #dcdfe6;

    &:hover {
      background-color: v-bind(lineColorValue);
      cursor: v-bind(lineIcon);
    }
  }
}

// region 左右布局样式
.leftRightBox {
  display: flex;
  height: 100%;
  width: 100%;

  .leftBox {
    flex: 0 0 auto;
    overflow: hidden;
  }

  .lfLineBox {
    @extend .publicLine;

    .line {
      height: 100%;
      width: v-bind(lineActiveWidth);
    }
  }

  .rightBox {
    flex: 1 1 auto;
    overflow: hidden;
  }

}

// endregion


// region 上下布局样式
.topBottomBox {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;

  .topBox {
    flex: 0 0 auto;
    overflow: hidden;
  }

  .tbLineBox {
    @extend .publicLine;

    .line {
      width: 100%;
      height: v-bind(lineActiveWidth);
    }
  }

  .bottomBox {
    flex: 1 1 auto;
    overflow: hidden;
  }

}

// endregion


// region 中间线的图标
.iconBox {
  .iconItem {
    position: absolute;
    z-index: 10;
    background-color: #dcdfe6;
    cursor: pointer;

    &:hover {
      background-color: v-bind(lineIconControllColor);
    }
  }

  .lrIcon {
    left: -8px;
    top: 50%;
  }

  .tnIcon {
    left: 50%;
    top: -8px;
    transform: rotateZ(90deg);
  }

}

// endregion

</style>